package ar.uade.distribuidas.tpo.servicios;

import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.base.AbstractDateTime;
import org.w3c.dom.Document;

import ar.uade.distribuidas.tpo.base.dominiodto.ClienteDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.CondicionDeVentaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.CotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.EstadoItemPedido;
import ar.uade.distribuidas.tpo.base.dominiodto.EstadoRemito;
import ar.uade.distribuidas.tpo.base.dominiodto.FacturaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemCotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemFacturaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemListaPrecioDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemPedidoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemRemitoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemSolicitudDeCotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.OrdenDePedidoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.RemitoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.RodamientoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.SolicitudDeCotizacionDTO;
import ar.uade.distribuidas.tpo.base.utils.FormatUtils;
import ar.uade.distribuidas.tpo.dao.CotizacionXmlDao;
import ar.uade.distribuidas.tpo.dao.FacturaXMLDao;
import ar.uade.distribuidas.tpo.dao.OrdenDePedidoXmlDao;
import ar.uade.distribuidas.tpo.dao.RemitoXmlDAO;
import ar.uade.distribuidas.tpo.dba.dominio.Contado;
import ar.uade.distribuidas.tpo.web.delegado.BD;

public class VentasServiceImpl implements VentasService {

	private static final int PLAZO = 30;

	private static float PORCENTAJE_GANANCIA = 0.5F;

	private static VentasServiceImpl instance;
	private static XmlService xmlService;

	private static BD gestion;

	public static VentasServiceImpl getInstancia() {
		if (instance == null) {
			instance = new VentasServiceImpl();
			xmlService = XmlServiceImpl.getInstancia("solicitud-de-cotizacion");
			gestion = BD.getInstance();
		}
		return instance;
	}

	@Override
	public List<Long> recibirSolicitudDeCotizacion(Document docu)
			throws Exception {

		List<Long> ids = new LinkedList<Long>();
		List<SolicitudDeCotizacionDTO> sc = xmlService
				.parseSolicitudDeCotizacion(docu);
		for (SolicitudDeCotizacionDTO sol : sc) {
			gestion.altaSolicitudDeCotizacion(sol);
			ids.add(sol.getId());
		}
		return ids;
	}

	@Override
	public String cotizarSolicitud(Long long1) {

		SolicitudDeCotizacionDTO solicitud = gestion
				.getSolicitudDeCotizacion(long1);

		CotizacionDTO cotizacion = new CotizacionDTO();
		cotizacion.setCliente(solicitud.getCliente());
		cotizacion.setCondicionesDeVentaDTO(solicitud.getCliente()
				.getCondiciones());
		cotizacion.setFechaDesde(this.getFecha());
		cotizacion.setId(long1);

		for (ItemSolicitudDeCotizacionDTO itemSol : solicitud.getItems()) {
			ItemCotizacionDTO itemCot = new ItemCotizacionDTO();
			itemCot.setItemSolicitudId(itemSol.getId());
			itemCot.setSolicitudId(solicitud.getId());
			itemCot.setCantidad(itemSol.getCantidad());

			ItemListaPrecioDTO itemMejorPrecio = gestion.getMejorPrecio(
					itemSol.getRodamiento(), itemSol.getCantidad());

			itemCot.setPrecio(this.calcularPrecio(itemMejorPrecio, itemCot,
					itemSol));
			itemCot.setItemListaPrecioId(itemMejorPrecio.getIdItem());

			cotizacion.getItemCotizacionDTO().add(itemCot);
		}
		gestion.altaCotizacion(cotizacion);

		return CotizacionXmlDao.getInstance().generarCotizacionXML(cotizacion);
	}

	private float calcularPrecio(ItemListaPrecioDTO itemMejorPrecio,
			ItemCotizacionDTO itemCot, ItemSolicitudDeCotizacionDTO itemSol) {

		//if (itemSol.getCantidad() <= itemMejorPrecio.getCantidadAsegurada()) { //Revisar el stock en todo caso
			float costo = (float) itemMejorPrecio.getCosto();
			return costo * (1 + PORCENTAJE_GANANCIA);
		//}

		//return 0;
	}

	private String getFecha() {
		return new LocalDate().toString(FormatUtils.DATE_FORMATTER);
	}

	@Override
	public Long recibirOrdenDePedido(Document docu)
			throws Exception {

		OrdenDePedidoXmlDao odpXmlDao = OrdenDePedidoXmlDao
				.getInstancia();
		OrdenDePedidoDTO odp = odpXmlDao.getOrdenDePedidoDTO(docu).get(0);
		// odp = getODP();

		BD.getInstance().altaOrdenDePedido(odp);

		return odp.getNumero();
	}

	@Override
	public String enviarPedido(Long idOdp) throws Exception {
		OrdenDePedidoDTO odp = BD.getInstance().getOrdenDePedido(idOdp);

		RemitoDTO remitoDTO = new RemitoDTO();
		remitoDTO.setClienteDTO(odp.getCliente());
		remitoDTO.setEstado(EstadoRemito.EMITIDO);
		remitoDTO.setFecha(LocalDate.now().toString(FormatUtils.DATE_FORMATTER));
		remitoDTO.setNumero(Integer.valueOf(odp.getNumero().toString()));
		List<ItemRemitoDTO> itemsRemito = new LinkedList<ItemRemitoDTO>();
		remitoDTO.setItemsRemito(itemsRemito);

		for (ItemPedidoDTO iPed : odp.getItemsPedido()) {
			ItemRemitoDTO iRem = new ItemRemitoDTO();
			ItemCotizacionDTO iCot = BD.getInstance().getItemCotizacion(
					iPed.getItemCotizacionId());
			iRem.setCantidad(iCot.getCantidad());
			iRem.setIdItem(iRem.getIdItem());
			iRem.setItemPedido(iPed);
			iRem.setNumeroRemito(remitoDTO.getNumero());

			ItemSolicitudDeCotizacionDTO itemSC = BD.getInstance()
					.getItemSolicitudDeCotizacion(iPed.getItemCotizacionId());

			remitoDTO.getItemsRemito().add(iRem);
		}

		BD.getInstance().altaRemito(remitoDTO);
		return RemitoXmlDAO.remitoToXmlString(remitoDTO);
	}

	@Override
	public String generarVenta(long cuilCliente) throws Exception {

		ClienteDTO cliente = BD.getInstance().getCliente(cuilCliente); // (Long.valueOf(cuilCliente));
		List<ItemPedidoDTO> itemsPedido = BD.getInstance().getItemsPedidoByEstado(EstadoItemPedido.ENVIADO);
		if (itemsPedido != null && !itemsPedido.isEmpty()) {
			FacturaDTO fact = new FacturaDTO();
			Map<Long, ItemRemitoDTO> mapa = BD.getInstance()
					.getMapItemPedidoItemRemito(itemsPedido);
			
			
			LocalDate hoy = new LocalDate();
			fact.setFechaEmision(hoy .toString(FormatUtils.DATE_FORMATTER));
			fact.setFechaVencimiento(hoy.plusDays(30).toString(FormatUtils.DATE_FORMATTER));
			
			fact.setCondicionVenta(BD.getInstance().getCliente(cuilCliente).getCondiciones().get(0));
			fact.setNumeroFactura(BD.getInstance().getProximoNumeroFactura());
			fact.setCliente(cliente);
			fact.setPrecio(0);
			fact.setItemsFactura(new LinkedList<ItemFacturaDTO>());
			
			for (ItemPedidoDTO i : itemsPedido) {
				ItemFacturaDTO itemF = new ItemFacturaDTO();
				ItemCotizacionDTO cot = BD.getInstance().getItemCotizacion(
						i.getItemCotizacionId());
				itemF.setCantidad(cot.getCantidad());
				if(cliente.getCondiciones()!= null && !cliente.getCondiciones().isEmpty())
					itemF.setPrecioTotal(cot.getPrecio() + (cot.getPrecio()*cliente.getCondiciones().get(0).getPorcentaje() /100));
				else
					itemF.setPrecioTotal(cot.getPrecio());
				
				itemF.setItemRemitoDTO(mapa.get(i.getId())); 
				 itemF.setPrecioUnitario(cot.getPrecio() / cot.getCantidad());
				fact.getItemsFactura().add(itemF);
				fact.setPrecio(itemF.getPrecioTotal()+fact.getPrecio());
				BD.getInstance().cambiarEstadoItem(i.getId(),
						EstadoItemPedido.FACTURADO);
			}

			BD.getInstance().altaFactura(fact);
			return FacturaXMLDao.generarFacturaXML(fact);

		}

		// creo una factura por cada condicion de venta incluyendo todos los
		// items entregados en varios remitos
		// Map<CondicionDeVentaDTO, FacturaDTO> facturasPorCDV = new
		// HashMap<CondicionDeVentaDTO, FacturaDTO>();
		//
		// for (RemitoDTO r : remitos) {
		// for (Entry<OrdenDePedidoDTO, List<ItemRemitoDTO>> entry :
		// r.getItemsPorOrdenDePedidoDTO().entrySet()) {
		// OrdenDePedidoDTO odp = entry.getKey();
		// List<ItemRemitoDTO> itemsRemito = entry.getValue();
		// CondicionDeVentaDTO cdv = odp.getCondicionVenta();
		// FacturaDTO factura;
		//
		// if (!facturasPorCDV.containsKey(cdv)) {
		// factura = new FacturaDTO();
		// facturasPorCDV.put(cdv, factura);
		//
		// factura.setCliente(cliente);
		// factura.setFechaEmision(new DateTime());
		// factura.setFechaVencimiento(factura.getFechaEmision().plusDays(PLAZO));
		// factura.setCondicionVenta(cdv);
		// factura.setNumeroFactura(BD.getInstance().getProximoNumeroFactura());
		// }
		//
		// factura = facturasPorCDV.get(cdv);
		//
		// for (ItemRemitoDTO i : itemsRemito) {
		//
		// ItemFacturaDTO itemFactura = new ItemFacturaDTO();
		// itemFactura.setCantidad(i.getCantidad());
		// itemFactura.setPrecioUnitario(this.findPrecio(i));
		// itemFactura.setPrecioTotal(itemFactura.getPrecioUnitario() *
		// itemFactura.getCantidad());
		// itemFactura.setRodamiento(i.getRodamiento());
		// itemFactura.setRemitoDTO(r);
		//
		// factura.getItemsFactura().add(itemFactura);
		// }
		//
		// }
		// }

		// String xmlFacturas = "";

		// for (FacturaDTO f : facturasPorCDV.values()) {
		// float precioTotal = 0;
		//
		// for(ItemFacturaDTO i : f.getItemsFactura()) {
		// precioTotal += i.getPrecioTotal();
		// }
		//
		// f.setPrecio(precioTotal);
		// BD.getInstance().altaFactura(f);
		// xmlFacturas.concat(FacturaXMLDao.generarFacturaXML(f));
		// }

		return "";
	}

	private float findPrecio(ItemRemitoDTO itemRemito) {

		RodamientoDTO cDTO = new RodamientoDTO();
		cDTO.setIdRodamiento(itemRemito.getItemPedido().getRodamientoId());
		RodamientoDTO r = BD.getInstance().getRodamiento(cDTO);

		if (r != null) {

			// for (ItemPedidoDTO itemPedido :
			// itemRemito.getItemPedido().getItemsPedido()) { solo hay un
			// itemPedido por itemRemito
			ItemCotizacionDTO itemCot = BD.getInstance().getItemCotizacion(
					itemRemito.getItemPedido().getItemCotizacionId());

			ItemSolicitudDeCotizacionDTO isc = BD.getInstance()
					.getItemSolicitudDeCotizacion(itemCot.getItemSolicitudId());

			if (r.equals(isc.getRodamiento().equals(r))) {
				return itemCot.getPrecio();
			}
			// }
		}
		return 0;
	}

}